﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace IniHelper
{
    public class IniContainer
    {
        [DllImport("kernel32")]
        private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
        [DllImport("kernel32")]
        private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);

        private Dictionary<string, Dictionary<string, List<string>>> iniAttributes;
        private string filePath = "";
        private string fileName = "";

        public void addIniValue(string section, string key, IList<string> values)
        {
            Dictionary<string, List<string>> valuesInSection = null;
            List<string> valuesInKey = null;
            
            if (!iniAttributes.TryGetValue(section, out valuesInSection))
            {
                valuesInSection = new Dictionary<string,List<string>>();
                iniAttributes.Add(section, valuesInSection);
            }
            if (!valuesInSection.TryGetValue(key, out valuesInKey))
            {
                valuesInKey = new List<string>();
                valuesInSection.Add(key, valuesInKey);
            }

            foreach (string value in values)
            {
                if (!valuesInKey.Contains(value))
                {
                    valuesInKey.Add(value);
                }
            }
        }

        public void addIniValue(string section, string key, string value)
        {
            Dictionary<string, List<string>> valuesInSection = null;
            List<string> valuesInKey = null;

            if (!iniAttributes.TryGetValue(section, out valuesInSection))
            {
                valuesInSection = new Dictionary<string, List<string>>();
                iniAttributes.Add(section, valuesInSection);
            }
            if (!valuesInSection.TryGetValue(key, out valuesInKey))
            {
                valuesInKey = new List<string>();
                valuesInSection.Add(key, valuesInKey);
            }

            if (!valuesInKey.Contains(value))
            {
                valuesInKey.Add(value);
            }
        }

        public void overwriteIniValues(string section, string key, IList<string> values)
        {
            Dictionary<string, List<string>> valuesInSection = null;
            List<string> valuesInKey = null;

            if (!iniAttributes.TryGetValue(section, out valuesInSection))
            {
                valuesInSection = new Dictionary<string, List<string>>();
                iniAttributes.Add(section, valuesInSection);
            }
            if (!valuesInSection.TryGetValue(key, out valuesInKey))
            {
                valuesInKey = new List<string>();
                valuesInSection.Add(key, valuesInKey);
            }
            valuesInKey.Clear();

            foreach (string value in values)
            {
                if (!valuesInKey.Contains(value))
                {
                    valuesInKey.Add(value);
                }
            }
        }

        public void overwriteIniValue(string section, string key, string value)
        {
            Dictionary<string, List<string>> valuesInSection = null;
            List<string> valuesInKey = null;

            if (!iniAttributes.TryGetValue(section, out valuesInSection))
            {
                valuesInSection = new Dictionary<string, List<string>>();
                iniAttributes.Add(section, valuesInSection);
            }
            if (!valuesInSection.TryGetValue(key, out valuesInKey))
            {
                valuesInKey = new List<string>();
                valuesInSection.Add(key, valuesInKey);
            }
            valuesInKey.Clear();

            valuesInKey.Add(value);
        }

        public void removeIniValue(string section, string key, string value)
        {
            Dictionary<string, List<string>> valuesInSection = null;
            List<string> valuesInKey = null;

            if (!iniAttributes.TryGetValue(section, out valuesInSection))
            {
                valuesInSection = new Dictionary<string, List<string>>();
                iniAttributes.Add(section, valuesInSection);
            }
            if (!valuesInSection.TryGetValue(key, out valuesInKey))
            {
                valuesInKey = new List<string>();
                valuesInSection.Add(key, valuesInKey);
            }

            if (valuesInKey.Contains(value))
            {
                valuesInKey.Remove(value);
            }
        }

        public static IniContainer createContainer(string project, string path)
        {
            IniContainer container = new IniContainer();
            container.filePath = path;
            container.fileName = project;

            return container;
        }

        private IniContainer()
        {
            iniAttributes = new Dictionary<string, Dictionary<string, List<string>>>();
        }

        public List<string> getValues(string section, string key)
        {
            List<string> valueList = null;
            Dictionary<string, List<string>> valuesInSection = null;

            if (!iniAttributes.TryGetValue(section, out valuesInSection))
            {
                return null;
            }
            else if (!valuesInSection.TryGetValue(key, out valueList))
            {
                return null;
            }

            return valueList;
        }

        public bool contains(string section, string key, string value)
        {
            Dictionary<string, List<string>> valuesInSection = null;
            List<string> valuesInKey = null;

            if (!iniAttributes.TryGetValue(section, out valuesInSection))
            {
                return false;
            }
            else if (!valuesInSection.TryGetValue(key, out valuesInKey))
            {
                return false;
            }
            else if (!valuesInKey.Contains(value))
            {
                return false;
            }
            return true;
        }

        private void writeToIni()
        {
            foreach (KeyValuePair<string, Dictionary<string, List<string>>> sectionPair in iniAttributes)
            {
                foreach (KeyValuePair<string, List<String>> keyPair in sectionPair.Value)
                {
                    string strBuffer = "";
                    foreach (string value in keyPair.Value)
                    {
                        strBuffer = strBuffer + value + ";";
                    }
                    strBuffer = strBuffer.Substring(0, strBuffer.Length - 1);
                    WritePrivateProfileString(sectionPair.Key, keyPair.Key, strBuffer, filePath + @"\" + fileName + ".ini");
                }
            }
        }

        private void loadFromIni(Dictionary<string, List<string>> loadList)
        {
            iniAttributes.Clear();

            foreach (KeyValuePair<string, List<string>> loadPairBySection in loadList)
            {
                Dictionary<string, List<string>> valueInSection = new Dictionary<string, List<string>>();
                iniAttributes.Add(loadPairBySection.Key, valueInSection);
                foreach (string keyValue in loadPairBySection.Value)
                {
                    StringBuilder inputBuffer = new StringBuilder(2048);
                    GetPrivateProfileString(loadPairBySection.Key, keyValue, "", inputBuffer, 2048, filePath + @"\" + fileName + ".ini");
                    List<string> valueList = inputBuffer.ToString().Split(';').ToList();
                    valueList.Remove("");
                    valueInSection.Add(keyValue, valueList);
                }
            }
        }

        public void save()
        {
            writeToIni();
        }

        public void load(Dictionary<string, List<string>> loadList)
        {
            loadFromIni(loadList);
        }

        public void setPath(string path)
        {
            filePath = path;
        }

        public void setName(string name)
        {
            fileName = name;
        }

        #region For further xml config file
        
        /// <summary>
        /// Can read xml file without knowing the attributes' name 
        /// </summary>
        public void loadAll()
        {
        }

        #endregion
    }
}
